package com.xz.common.config;

import org.apache.commons.io.IOUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author shafulin
 * @date 2023/4/19 9:39
 * @description 请求流支持多次获取
 * 参考文档：https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247582237&idx=1&sn=55dde73d6fa87a5c2cec7d559df1ee4f&chksm=eb51072bdc268e3dc6827d7f6b299d46654ca6cfb3d5334e01e33bd997fcbae060f41674c407&mpshare=1&scene=1&srcid=04170MjxrcAqeubcSdWP0D46&sharer_sharetime=1681703068327&sharer_shareid=cb83a8a406e38d7526ca4f2fc44eeb13&key=93e34dd7a4c876e2a5c05cbc004181eb9e3b84aa43f37d6989e589feefc347e11375334c66f1b7b78e479dbf32f35015c24ac54fdb0bee687352cddb32137adbaae763b04e1d9701d98d5f6d082faab69bf17da51cbf75cfebaf7601d44528b8df16fe60becd6f6508243973e2b32799ac11815b1b3c35abbd7639d69648fa32&ascene=1&uin=MTMwMTQxOTA3Mg%3D%3D&devicetype=Windows+10+x64&version=63090217&lang=zh_CN&countrycode=CN&exportkey=n_ChQIAhIQWSG9aHYI5p3LdyxBRtV9URLqAQIE97dBBAEAAAAAAG8sDxnH8VIAAAAOpnltbLcz9gKNyK89dVj07Z13pBEITcyiYH8qDOx%2B5OrXsIu8V3PjBSe7EOcu3OrGa9wZhTIo9%2Bzl%2F59wPs%2B72EpzTUod2K2gx9FsXSThdQZZkEK0E20V3p7p4fZ84aBkiBwjsjMUx6XMy9ERsq25KZ8FGjYY48TjtFEBnINIAbJ8sSLqoB%2FowuCs096I424JDMheqgHE6nwYr1BkLaRaHmzIeS4FOuseGdCF0pzzqPUAoip3wkNxK8v5K%2BFKbkKTI%2BSi2HMfytzQIyk4MzfC%2BdUrlg%3D%3D&acctmode=0&pass_ticket=NlvpRmUeTQsJstpjatgV5QF%2FF31P2bL%2FL5bYVaJOstcsQa3bpEdt8FbbwHINZl24oWGdTi%2FFKvzpWGPZoX5bjQ%3D%3D&wx_header=1&fontgear=2
 */
public class InputStreamHttpServletRequestWrapper extends HttpServletRequestWrapper {

    /**
     * 用于缓存输入流
     */
    private ByteArrayOutputStream cachedBytes;

    public InputStreamHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null) {
            // 首次获取流时，将流放入 缓存输入流 中
            cacheInputStream();
        }

        // 从 缓存输入流 中获取流并返回
        return new CachedServletInputStream(cachedBytes.toByteArray());
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    /**
     * 首次获取流时，将流放入 缓存输入流 中
     */
    private void cacheInputStream() throws IOException {
        // 缓存输入流以便多次读取。为了方便, 我使用 org.apache.commons IOUtils
        cachedBytes = new ByteArrayOutputStream();
        IOUtils.copy(super.getInputStream(), cachedBytes);
    }

    /**
     * 读取缓存的请求正文的输入流
     * <p>
     * 用于根据 缓存输入流 创建一个可返回的
     */
    public static class CachedServletInputStream extends ServletInputStream {

        private final ByteArrayInputStream input;

        public CachedServletInputStream(byte[] buf) {
            // 从缓存的请求正文创建一个新的输入流
            input = new ByteArrayInputStream(buf);
        }

        @Override
        public boolean isFinished() {
            return false;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener listener) {

        }

        @Override
        public int read() throws IOException {
            return input.read();
        }
    }
}
